#include "vl_message_queue.h"

using namespace VL;

namespace VL {

/**
 * @Author: CimZzz
 * @Date: 2022-08-27 19:29:52
 * 
 * 时间消息队列线程
 */
struct _VLTimerQueueThreadDelay {
	// 目标时间
	std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> goalTime;
	// 是否为队首消息
	bool isFirst;
	// 消息数据指针
	std::shared_ptr<VLMessageQueueData> dataPtr;
	// 下一个延迟消息
	std::shared_ptr<_VLTimerQueueThreadDelay> nextPtr;
};

}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 08:22:13
 * 
 * 构造函数
 * 
 * @param period 周期时间, 单位毫秒, 不得小于 500 毫秒
 */
VLTimerQueueThread::VLTimerQueueThread(unsigned int period): VLMessageQueueThread(), timerCallback(nullptr), delayList(nullptr), timer([&]{
	this->handleTimerCallback();
}, false, period) {
	
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 08:22:13
 * 
 * 构造函数
 * 
 * @param looper 消息队列回调
 * @param period 周期时间, 单位毫秒, 不得小于 500 毫秒
 */
VLTimerQueueThread::VLTimerQueueThread(VLMessageQueueLooper looper, unsigned int period)
	: VLMessageQueueThread(looper), timerCallback(nullptr), delayList(nullptr), timer([&]{
	this->handleTimerCallback();
}, false, period) {
	
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 08:22:13
 * 
 * 构造函数
 * 
 * @param timerCallback 定时器回调
 * @param period 周期时间, 单位毫秒, 不得小于 500 毫秒
 */
VLTimerQueueThread::VLTimerQueueThread(TimerCallback timerCallback, unsigned int period)
	: VLMessageQueueThread(), timerCallback(timerCallback), delayList(nullptr), timer([&]{
	this->handleTimerCallback();
}, false, period) {

}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 08:22:13
 * 
 * 构造函数
 * 
 * @param looper 消息队列回调
 * @param timerCallback 定时器回调
 * @param period 周期时间, 单位毫秒, 不得小于 500 毫秒
 */
VLTimerQueueThread::VLTimerQueueThread(VLMessageQueueLooper looper, TimerCallback timerCallback, unsigned int period)
	: VLMessageQueueThread(looper), timerCallback(timerCallback), delayList(nullptr), timer([&]{
	this->handleTimerCallback();
}, false, period) {

}

/**
 * @Author: CimZzz
 * @Date: 2022-08-27 20:13:53
 * 
 * 清空消息队列中全部消息
 */
void VLTimerQueueThread::clear() {
	this->mutex.lock();
	this->delayList.reset();
	this->mutex.unlock();
	
	VLMessageQueueThread::clear();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-27 19:13:08
 * 
 * 延迟入队数据
 * 
 * @param dataPtr 消息队列数据指针
 * @param delayTime 延迟时间, 单位毫秒
 */
void VLTimerQueueThread::delay(VLMessageQueueData* dataPtr, uint32_t delayTime) {
	std::lock_guard<std::mutex> locker(this->mutex);
	if(this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_Destroy ||
		this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_WaitDestroy) {
		// 待销毁状态不再接收延迟数据
		delete dataPtr;
		return;
	}
	this->insertDelayMessage(std::shared_ptr<VLMessageQueueData>(dataPtr), delayTime, false);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-27 19:13:08
 * 
 * 延迟入队数据
 * 
 * @param dataPtr 消息队列数据指针
 * @param delayTime 延迟时间, 单位毫秒
 */
void VLTimerQueueThread::delay(std::shared_ptr<VLMessageQueueData> dataPtr, uint32_t delayTime) {
	std::lock_guard<std::mutex> locker(this->mutex);
	if(this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_Destroy ||
		this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_WaitDestroy) {
		// 待销毁状态不再接收延迟数据
		return;
	}

	this->insertDelayMessage(dataPtr, delayTime, false);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-27 19:13:08
 * 
 * 延迟入队数据, 插入到队首
 * 
 * @param dataPtr 消息队列数据指针
 * @param delayTime 延迟时间, 单位毫秒
 */
void VLTimerQueueThread::delayFirst(VLMessageQueueData* dataPtr, uint32_t delayTime) {
	std::lock_guard<std::mutex> locker(this->mutex);
	if(this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_Destroy ||
		this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_WaitDestroy) {
		// 待销毁状态不再接收延迟数据
		delete dataPtr;
		return;
	}
	this->insertDelayMessage(std::shared_ptr<VLMessageQueueData>(dataPtr), delayTime, true);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-27 19:13:08
 * 
 * 延迟入队数据, 插入到队首
 * 
 * @param dataPtr 消息队列数据指针
 * @param delayTime 延迟时间, 单位毫秒
 */
void VLTimerQueueThread::delayFirst(std::shared_ptr<VLMessageQueueData> dataPtr, uint32_t delayTime) {
	std::lock_guard<std::mutex> locker(this->mutex);
	if(this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_Destroy ||
		this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_WaitDestroy) {
		// 待销毁状态不再接收延迟数据
		return;
	}

	this->insertDelayMessage(dataPtr, delayTime, true);
}

/**
 * @Author: CimZzz
 * @Date: 2022-09-07 18:15:53
 * 
 * 立即调度一次定时回调
 */
void VLTimerQueueThread::scheduleImmediately() {
	std::lock_guard<std::mutex> locker(this->mutex);
	if(this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_Destroy ||
		this->getMessageQueueThreadStatus() == VLMessageQueueThreadStatus::MQTS_WaitDestroy) {
		// 待销毁状态不再发送触发定时消息
		return;
	}

	this->timer.scheduleOnce();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 00:56:23
 * 
 * 消息队列启动回调
 */
void VLTimerQueueThread::onLoopBegin() {
	this->timer.beginSchedule();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 00:55:08
 * 
 * 执行消息队列消费回调
 * 
 * @param dataPtr 消息数据指针
 */
void VLTimerQueueThread::onLoop(const std::shared_ptr<VLMessageQueueData>& dataPtr) {
	if(dataPtr.get() == nullptr) {
		return;
	}
	if(dataPtr->getTypeCode() == 0xFFFFFF) {
		this->onTimer();
	} else {
		this->callLooper(dataPtr);
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-27 20:22:45
 * 
 * 消息队列线程期望终止
 * 由 [destroyUntil 触发]
 */
void VLTimerQueueThread::onLooperWannaEnd() {
	this->delayList.reset();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 08:30:38
 * 
 * 触发定时器回调
 */
void VLTimerQueueThread::onTimer() {
	this->callTimer();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 00:56:41
 * 
 * 消息队列终止回调
 */
void VLTimerQueueThread::onLoopEnd() {
	this->timer.stopSchedule();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 08:30:52
 * 
 * 调用定时器回调
 */
void VLTimerQueueThread::callTimer() {
	// 检查延迟消息
	if(this->timerCallback) {
		this->timerCallback();
	}
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-27 19:34:11
 * 
 * 插入延迟消息数据
 * 
 * @param dataPtr 数据指针
 * @param delayTime 延迟时间, 单位为毫秒
 * @param isFirst 是否为队首消息
 */
void VLTimerQueueThread::insertDelayMessage(const std::shared_ptr<VLMessageQueueData>& dataPtr, uint32_t delayTime, bool isFirst) {
	auto goalTime = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
	goalTime += std::chrono::milliseconds(delayTime);
	std::shared_ptr<_VLTimerQueueThreadDelay> delayDataPtr(new _VLTimerQueueThreadDelay {
		.goalTime = goalTime,
		.isFirst = isFirst,
		.dataPtr = dataPtr,
		.nextPtr = std::shared_ptr<_VLTimerQueueThreadDelay>(nullptr)
	});
	if(this->delayList.get() == nullptr) {
		this->delayList = delayDataPtr;
		return;
	}
	
	auto delayItemPtr = std::static_pointer_cast<_VLTimerQueueThreadDelay, void>(this->delayList);
	std::shared_ptr<_VLTimerQueueThreadDelay> parentPtr(nullptr);
	while(delayItemPtr.get() != nullptr) {
		if(delayItemPtr->goalTime > delayDataPtr->goalTime) {
			if(parentPtr.get() == nullptr) {
				delayDataPtr->nextPtr = delayItemPtr;
				this->delayList = delayDataPtr;
				return;
			} else {
				delayDataPtr->nextPtr = delayItemPtr;
				parentPtr->nextPtr = delayDataPtr;
				return;
			}
		}
		parentPtr = delayItemPtr;
		delayItemPtr = delayItemPtr->nextPtr;
	}
	parentPtr->nextPtr = delayDataPtr;
}

/**
 * @Author: CimZzz
 * @Date: 2022-09-07 18:18:26
 * 
 * 处理定时器回调
 */
void VLTimerQueueThread::handleTimerCallback() {
	this->enqueueFirst(true, 0xFFFFFF);
	if(this->delayList.get() != nullptr) {
		this->mutex.lock();
		if(this->delayList.get() == nullptr) {
			this->mutex.unlock();
			return;
		}

		auto currentGoalTime = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
		std::shared_ptr<_VLTimerQueueThreadDelay> pendingDelayList(nullptr);
		auto delayItemPtr = std::static_pointer_cast<_VLTimerQueueThreadDelay, void>(this->delayList);
		std::shared_ptr<_VLTimerQueueThreadDelay> parentPtr(nullptr);
		while(delayItemPtr.get() != nullptr && delayItemPtr->goalTime <= currentGoalTime) {
			if(pendingDelayList.get() == nullptr) {
				pendingDelayList = delayItemPtr;
			}
			parentPtr = delayItemPtr;
			delayItemPtr = delayItemPtr->nextPtr;
		}

		if(pendingDelayList.get() != nullptr) {
			// 有需要执行的延迟消息
			this->delayList = delayItemPtr;
			parentPtr->nextPtr.reset();
		}

		this->mutex.unlock();

		while(pendingDelayList.get() != nullptr) {
			if(pendingDelayList->isFirst) {
				this->enqueueFirst(pendingDelayList->dataPtr);
			} else {
				this->enqueue(pendingDelayList->dataPtr);
			}
			pendingDelayList = pendingDelayList->nextPtr;
		}
	}
}